#include "EventLoop.hpp"
#include "TcpConnect.hpp"
#include <cerrno>
#include <climits>
#include <cstdint>
#include <cstdlib>
#include <mutex>
#include <sys/epoll.h>


namespace wd{


EventLoop::EventLoop(Acceptor & acceptor)
:_epfd(epollCreate())
,_eventfd(eventfdCreate())
,_mutex()
,_acceptor(acceptor)
,_isLooping(false)
,_events(1000)
{
    addEpollReadEvent(_acceptor.fd());
    addEpollReadEvent(_eventfd);
}

EventLoop::~EventLoop(){
    close(_epfd);
}

int EventLoop::epollCreate(){
    int epfd = epoll_create1(0);
    if(epfd < 0){
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }
    return epfd;
}

int EventLoop::eventfdCreate(){
    int fd = eventfd(0,0);
    if(fd < 0){
        perror("eventfd");
        exit(EXIT_FAILURE);
    }
    return fd;
}

void EventLoop::loop(){
    _isLooping = true;
    while(_isLooping == true){
        waitEpollFd();
    }
}
    
void EventLoop::unloop(){
    _isLooping = false;
}

void EventLoop::setAllCallbacks(const Callback & onConnection,
                         const Callback & onMessage,
                         const Callback & onClose){

    _onConnection = onConnection;
    _onMessage = onMessage;
    _onClose = onClose;
}


void EventLoop::waitEpollFd(){
    int readynum = epoll_wait(_epfd,_events.data(),_events.size(),10000);
    if(readynum == -1 && errno == EINTR){
        return;
    }else if(readynum == -1){
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }else if(readynum == 0){
        printf("epoll timeout\n");
    }else{
        for(int i = 0;i < readynum; ++i){
            int fd = _events[i].data.fd;
            if(fd == _acceptor.fd()){ //新连接
                handleNewConnection();
            }else if(fd == _eventfd){
                handleReadEvent();
                doPendingFunctors();
            }
            else{
                handleMessage(fd);
            }
        }

    }
}

void EventLoop::handleNewConnection(){
    //accept客户端连接
    int clientfd = _acceptor.accept();
    //增加epoll监听
    addEpollReadEvent(clientfd);
    //创建客户端的TcpConnection
    _conns.insert(std::make_pair(clientfd,
                                 TcpConnectionptr(new TcpConnection(clientfd,this))));
    //将回调函数赋值给TcpConnection
    _conns[clientfd]->setAllCallbacks(_onConnection,
                                      _onMessage,
                                      _onClose);
    _conns[clientfd]->handleNewConnectionCallback();
}

void EventLoop::handleMessage(int clientfd){
    auto it = _conns.find(clientfd);
    if(it != _conns.end()){
        if(it->second->isclose()==true){
            //连接已断开
            delEpollReadEvent(clientfd);
            it->second->handleCloseCallback();
        }else{
            it->second->handleMessageCallback();
        }
    }

}

void EventLoop::addEpollReadEvent(int netfd){
    struct epoll_event ev;
    ev.data.fd = netfd;
    ev.events = EPOLLIN;
    epoll_ctl(_epfd,EPOLL_CTL_ADD,netfd,&ev);
}
    
void EventLoop::delEpollReadEvent(int netfd){
    struct epoll_event ev;
    ev.data.fd = netfd;
    epoll_ctl(_epfd,EPOLL_CTL_DEL,netfd,&ev);
    
}


void EventLoop::runInLoop(Functor && cb){
    std::unique_lock<std::mutex> _ul(_mutex);
    _pendingFunctors.push_back(cb);

    wakeup(); //通知主线程执行,唤醒eventfd的读事件

}

void EventLoop::handleReadEvent() //read,清零
{
    uint64_t howmany = 0;
    int ret = read(_eventfd,&howmany,sizeof(howmany));
    printf("\nhowmany: %ld\n",howmany);

    if(ret != sizeof(howmany)){
        perror("read");
    }

}

void EventLoop::wakeup()  //write
{
    uint64_t one = 1;
    int ret = write(_eventfd, &one, sizeof(one));
    if(ret != sizeof(one)){
        perror("write");
    }
}
    
void EventLoop::doPendingFunctors() //执行callback函数
{   
    printf("\ndo PendingFunctors\n");
    vector<Functor> temp;
    {
        std::unique_lock<std::mutex> ul(_mutex);
        temp.swap(_pendingFunctors);
    }
    for(auto & f: temp){
        f();
    }
}


}
